﻿using System;
using System.Collections.Generic;
using Sinacor.Infra.Core.ProcessManager.Server;
using Sinacor.Infra.Common.Exceptions;
using Sinacor.Infra.Service.ExceptionHandling;
using PSE.ProcessManager.Server.Process.Security;
using Sinacor.Infra.Core.ProcessManager.Server.Security;
using Sinacor.Infra.Service.Validation;


namespace Sinacor.Process.Bovespa.ControleMovimentoBolsa.Server.ProcessLogic
{
    public class FechamentoMovimentoBolsa : BaseProcessLogic
    {
        #region Campos

        private int _erroMovimentoFechado = 109694;
        private int _erroMovimentoOrdensAberto = 109696;
        private int _erroNaoEsperado = 109693;
        private int _erroObjetoNulo = 109691;
        private int _erroSemPermissaoAcesso = 109692;

        #endregion

        #region Propriedades

        public int ErroMovimentoFechado
        {
            get { return _erroMovimentoFechado; }
            set { _erroMovimentoFechado = value; }
        }


        public int ErroMovimentoOrdensAberto
        {
            get { return _erroMovimentoOrdensAberto; }
            set { _erroMovimentoOrdensAberto = value; }
        }


        public int ErroNaoEsperado
        {
            get { return _erroNaoEsperado; }
            set { _erroNaoEsperado = value; }
        }


        public int ErroObjetoNulo
        {
            get { return _erroObjetoNulo; }
            set { _erroObjetoNulo = value; }
        }


        public int ErroSemPermissaoAcesso
        {
            get { return _erroSemPermissaoAcesso; }
            set { _erroSemPermissaoAcesso = value; }
        }
        #endregion

        #region Métodos

        /// <summary>
        /// Efetua consistências no movimento bolsa.
        /// </summary>
        /// <param name="entity"></param>
        private ProcessEntity.MensagemSimulacao ConsistirMovimento(ProcessEntity.Parameter.FiltroFechamentoMovimento entity)
        {
            ResourceAccess.FechamentoMovimentoBolsa fechamentoMovimentoBolsa = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.Server.ResourceAccess.FechamentoMovimentoBolsa();
            ProcessEntity.MensagemSimulacao message = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.MensagemSimulacao();
            ProcessEntity.Resultado resultado = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.Resultado();
            resultado.Sucesso = true;
            message.Inconsistencias = new List<Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.Enum.TipoConsistencia>();
            resultado = fechamentoMovimentoBolsa.ConsistirMovimento(entity);
            if (resultado.Sucesso == true)
            {
                ResourceAccess.FechamentoMovimentoBolsa FechamentoMovimentoBolsa = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.Server.ResourceAccess.FechamentoMovimentoBolsa();
                if (fechamentoMovimentoBolsa.VerificarConsistenciaMovimento(ProcessEntity.Enum.TipoConsistencia.CI))
                {
                    message.Inconsistencias.Add(ProcessEntity.Enum.TipoConsistencia.CI);
                }
                else
                {
                    if (fechamentoMovimentoBolsa.VerificarConsistenciaMovimento(ProcessEntity.Enum.TipoConsistencia.ALC))
                    {
                        message.Inconsistencias.Add(ProcessEntity.Enum.TipoConsistencia.ALC);
                    }
                    else
                    {
                        if (fechamentoMovimentoBolsa.VerificarConsistenciaMovimento(ProcessEntity.Enum.TipoConsistencia.JUS))
                        {
                            message.Inconsistencias.Add(ProcessEntity.Enum.TipoConsistencia.JUS);
                        }
                        else
                        {
                            if (fechamentoMovimentoBolsa.VerificarConsistenciaMovimento(ProcessEntity.Enum.TipoConsistencia.CLI))
                            {
                                message.Inconsistencias.Add(ProcessEntity.Enum.TipoConsistencia.CLI);
                            }
                            else
                            {
                                if (fechamentoMovimentoBolsa.VerificarConsistenciaMovimento(ProcessEntity.Enum.TipoConsistencia.TER))
                                {
                                    message.Inconsistencias.Add(ProcessEntity.Enum.TipoConsistencia.TER);
                                }
                                else
                                {
                                    if (!fechamentoMovimentoBolsa.VerificarConsistenciaMovimento(ProcessEntity.Enum.TipoConsistencia.FEC))
                                    {
                                        message.Inconsistencias.Add(ProcessEntity.Enum.TipoConsistencia.FEC);
                                    }
                                    message.Inconsistencias.Add(ProcessEntity.Enum.TipoConsistencia.Todas);
                                    message.Sucesso = false;
                                }
                            }
                        }
                    }
                }


            }
            else
            {
                if (resultado.CodigoErro == -1)
                {
                    throw new BusinessException(ErroNaoEsperado);
                }
                else
                {
                    this.TratarExcecoes(resultado);
                }
            }

            return message;
        }

        /// <summary>
        /// Fecha o movimento faturamento bolsa.
        /// </summary>
        /// <param name="entity"></param>
        public ProcessEntity.MensagemFechamento FecharMovimento(ProcessEntity.Parameter.FiltroFechamentoMovimento entity)
        {
            ProcessEntity.Resultado resultado = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.Resultado();
            ResourceAccess.FechamentoMovimentoBolsa fechamentoMovimentoBolsa = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.Server.ResourceAccess.FechamentoMovimentoBolsa();
            ProcessEntity.MensagemFechamento mensagemFechamento = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.MensagemFechamento();

            if (entity != null)
            {
                if (this.VerificarPermissaoAcesso())
                {
                    SinacorValidation validation = new SinacorValidation();
                    validation.Validate<ProcessEntity.Parameter.FiltroControleMovimento>(entity);
                    validation.Validate();
                    validation = null;

                    if (this.VerificarMovimentoAberto())
                    {
                        if (this.VerificarModuloOrdensInstalado())
                        {
                            if (!this.VerificarMovimentoOrdensFechado())
                            {
                                throw new BusinessException(ErroMovimentoOrdensAberto);
                            }
                        }
                        mensagemFechamento = 
                            new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.MensagemFechamento() {
                                Sucesso = true   
                            };
                        mensagemFechamento.MensagemSimulacao = this.SimularFechamento(entity);
                        if (mensagemFechamento.MensagemSimulacao.Sucesso == true)
                        {
                            fechamentoMovimentoBolsa.AtualizarMovimentoEmFechamento();
                            resultado = fechamentoMovimentoBolsa.FecharMovimento(entity);

                            if (resultado.Sucesso == true)
                            {
                                fechamentoMovimentoBolsa.AtualizarMovimentoFechado();
                                return mensagemFechamento;
                            }
                            else
                            {
                                ResourceAccess.AberturaMovimentoBolsa aberturaMovimentoBolsa = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.Server.ResourceAccess.AberturaMovimentoBolsa();
                                aberturaMovimentoBolsa.AtualizarMovimentoAberto();
                                if (resultado.CodigoErro == -1)
                                {
                                    throw new BusinessException(ErroNaoEsperado);
                                }
                                else
                                {
                                    this.TratarExcecoes(resultado);
                                }
                            }

                        }
                        else
                        {
                            mensagemFechamento.Sucesso = false;
                            return mensagemFechamento;
                        }
                    }
                    else
                    {
                        throw new BusinessException(ErroMovimentoFechado);
                    }

                }
                else
                {
                    throw new BusinessException(ErroSemPermissaoAcesso);
                }
            }
            else
            {
                throw new BusinessException(ErroObjetoNulo);
            }
            return mensagemFechamento;
        }


        /// <summary>
        /// Persiste a inconsistencia do movimento conforme o tipo informado.
        /// </summary>
        /// <param name="entity"></param>
        private void PersistirInconsistencia(ProcessEntity.Enum.TipoConsistencia entity)
        {
            ProcessEntity.Resultado resultado = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.Resultado();
            ResourceAccess.FechamentoMovimentoBolsa fechamentoMovimentoBolsa = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.Server.ResourceAccess.FechamentoMovimentoBolsa();
            if (entity != ProcessEntity.Enum.TipoConsistencia.Todas)
            {
                resultado = fechamentoMovimentoBolsa.PersistirInconsistenciaMovimento(entity);
                if (!resultado.Sucesso)
                {
                    if (resultado.CodigoErro == -1)
                    {
                        throw new BusinessException(ErroNaoEsperado);
                    }
                    else
                    {
                        this.TratarExcecoes(resultado);
                    }
                }
            }
            //verdiagrama

            //Verificar diagrama de atividades
            //FechamentoMovimentoBolsa.
            //PersistirInconsistencia()       
        }

        /// <summary>
        /// Persiste as inconsistencias no banco de dados.
        /// </summary>
        /// <param name="entity"></param>
        private void PersistirInconsistencias(ProcessEntity.MensagemSimulacao entity)
        {
            foreach (ProcessEntity.Enum.TipoConsistencia item in entity.Inconsistencias)
            {
                this.PersistirInconsistencia(item);

            }

            //Para cada tipo de inconsistencia,
            //contida na lista representada pela
            //propriedade "Inconsistencias" da
            //mensagem de simulação, consumir o
            //método PersistirInconsistencia()
            //informando no parametro o tipo de
            //consistência lida.
        }

        /// <summary>
        /// Simula o fechamento do movimento bolsa
        /// </summary>
        /// <param name="entity"></param>
        public ProcessEntity.MensagemSimulacao SimularFechamento(ProcessEntity.Parameter.FiltroFechamentoMovimento entity)
        {
            // Avaliar Diagrama pois existe inconsistencias
            ProcessEntity.MensagemSimulacao mensagemSimulacao = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.MensagemSimulacao();
            if (entity != null)
            {

                if (VerificarPermissaoAcesso())
                {
                    // Validar RuleSet
                    if (VerificarMovimentoAberto())
                    {
                        mensagemSimulacao = this.ConsistirMovimento(entity);

                        if (mensagemSimulacao.Inconsistencias.Count > 0)
                        {
                            if (entity.ProcessaComInconsistencia)
                            {
                                this.PersistirInconsistencia(ProcessEntity.Enum.TipoConsistencia.Todas);
                                mensagemSimulacao.Sucesso = true;
                            }
                        }
                        return mensagemSimulacao;
                    }
                    else
                    {
                        throw new BusinessException(ErroMovimentoFechado);
                    }

                }
                else
                {
                    throw new BusinessException(ErroSemPermissaoAcesso);
                }

            }
            else
            {
                throw new BusinessException(ErroObjetoNulo);
            }
        }

        /// <summary>
        /// Trata as exceções geradas na execução da abertura.
        /// </summary>
        /// <param name="entity"></param>
        private void TratarExcecoes(ProcessEntity.Resultado entity)
        {
            if (entity != null)
            {
                if (String.IsNullOrEmpty(entity.Argumentos))
                {
                    throw new BusinessException(entity.CodigoErro)
                    {
                        LogData = entity.DescricaoErro
                    };
                }
                else
                {
                    throw new BusinessException(entity.CodigoErro, ErrorMessage.ConvertXmlArgumentsToParameters(entity.Argumentos));
                }
            }
            else
            {
                throw new BusinessException(ErroNaoEsperado);
            }
        }

        /// <summary>
        /// Verifica se o usuário possui o módulo de ordens instalado.
        /// </summary>
        private bool VerificarModuloOrdensInstalado()
        {
            return (new Communication.Acesso()).VerificarSistemaInstalado("ORD");
        }

        /// <summary>
        /// Verifica se o estado do movimento atual está aberto
        /// </summary>
        private bool VerificarMovimentoAberto()
        {
            ProcessEntity.InformacoesMovimento informacoesMovimento = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.InformacoesMovimento();
            Communication.ControleMovimentoBolsa controleMovimentoBolsa = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.Server.Communication.ControleMovimentoBolsa();
            informacoesMovimento = controleMovimentoBolsa.ObterInformacoesMovimento(new ProcessEntity.DataMovimento());

            if (informacoesMovimento.EstadoMovimento == ProcessEntity.Enum.TipoMovimento.Aberto)
            {
                return true;
            }
            else
            {
                return false;
            }

        }

        /// <summary>
        /// Verifica se o movimento de ordens está Fechado.
        /// </summary>
        private bool VerificarMovimentoOrdensFechado()
        {
            ProcessEntity.InformacoesMovimento informacoesMovimento = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.ProcessEntity.InformacoesMovimento();

            Communication.ControleMovimentoOrdens controleMovimentoOrdens = new Sinacor.Process.Bovespa.ControleMovimentoBolsa.Server.Communication.ControleMovimentoOrdens();
            informacoesMovimento = controleMovimentoOrdens.ObterInformacoesMovimento(new ProcessEntity.DataMovimento());
            if (informacoesMovimento.EstadoMovimento == ProcessEntity.Enum.TipoMovimento.Fechado)
            {
                return true;
            }
            else
            {
                return false;
            }

        }

        /// <summary>
        /// Verificar se o usuário possui acesso para fechar o movimento.
        /// </summary>
        private bool VerificarPermissaoAcesso()
        {
            if (!AuthorizationContext<SinacorAuthorizationContext>.Current.CheckUserAccess("BFECHA", "BOL"))
            {
                throw new BusinessException(ErroSemPermissaoAcesso);
            }
            return true;
        }
        #endregion
    }

}